#include <process.h>	// thread handles
#include "Block.h"

// Constructor
Block::Block(char *index, int size) {
	// default link list values
	this->prev = this->next = NULL;

	// store index & size
	this->index = _strdup(index);
	this->size = size;

	// initialize temporary index store
	this->sindex = NULL;

	// initialize the status of each todo
	this->handles = new HANDLE[this->size];
	this->status = new char[this->size];

	// initial values of status counts
	this->counts[0] = this->size;
	this->counts[1] = 0;
	this->counts[2] = 0;

	// status value is null until a thread has been added
	for(int loop = 0; loop < this->size; loop ++) {
		this->status[loop] = 0;
		this->handles[loop] = NULL;
	}
}

// Deconstructor
Block::~Block() {
	if(this->sindex) {
		OPENSSL_free(this->sindex);
	}
	delete[] this->status;
	delete[] this->handles;

	free(this->index);
}


// returns total number of todos in 'pending' state
int Block::getPending() {
	int count = 0;

	for(int loop = 0; loop < this->size; loop ++) {
		// find an index that is pending
		if(status[loop] == NULL) {
			count ++;
		}
	}

	return count;
}

// returns total number of todos in 'active' state
int Block::getActive() {
	int count = 0;

	for(int loop = 0; loop < this->size; loop ++) {
		// find an index that is pending
		if(status[loop] == 1) {
			count ++;
		}
	}

	return count;
}

// returns total number of todos in 'complete' state
int Block::getComplete() {
	int count = 0;

	for(int loop = 0; loop < this->size; loop ++) {
		// find an index that is pending
		if(status[loop] == 2) {
			count ++;
		}
	}

	return count;
}

// a thread is started, keep a tally
bool Block::thread_start() {
	for(int loop = 0; loop < this->size; loop ++) {
		// find an index that is pending
		if(status[loop] == NULL) {
			status[loop] = 1;
			return true;
		}
	}

	return false;
}

// a thread is complete, keep a tally
bool Block::thread_complete() {
	for(int loop = 0; loop < this->size; loop ++) {
		// find an index that is active
		if(status[loop] == 1) {
			status[loop] = 2;
			return true;
		}
	}

	return false;
}

// whether block is complete
bool Block::isComplete() {
	// update status counts
//	this->update();

	// return if all todos are complete
	if(this->getComplete() == this->size) {
		return true;
	}

	return false;
}

/*
// returns the next index to start
char* Block::getNextIndex() {
	for(int loop = 0; loop < this->size; loop ++) {
		// first check if a thread is being tracked
		if(status[loop] == NULL) {
			BIGNUM *tmp = BN_new();
			BN_dec2bn(&(tmp), this->index);
			BN_add_word(tmp, loop);
			if(this->sindex) {
				OPENSSL_free(this->sindex);
			}
			this->sindex = BN_bn2dec(tmp);
			BN_free(tmp);
			return this->sindex;
		}
	}

	return NULL;
}

// track the todo thread
bool Block::track(HANDLE todo) {
	for(int loop = 0; loop < this->size; loop ++) {
		// first check if a thread is being tracked
		if(status[loop] == NULL) {
			status[loop] = 1;
			handles[loop] = todo;
			return true;
		}
	}

	return false;
}

// updates the status of todos
void Block::update() {
	// reset counts
	this->counts[0] = this->counts[1] = this->counts[2] = 0;

	// loop through all threads checking status
	for(int loop = 0; loop < this->size; loop ++) {
		// first check if a thread is being tracked
		if(status[loop] == 0) {
			// no thread exists, pending
//			printf("P");
			this->counts[0] ++;
			continue;
		}
		if(status[loop] == 2) {
			// thread has completed
//			printf("C");
			this->counts[2] ++;
			continue;
		}
		if(status[loop] == 3) {		// used by drone(stbd_t) to notify server that thread is complete
			// thread has completed
//			printf("C");
			this->counts[2] ++;
			continue;
		}


		// check thread status
		switch(WaitForSingleObject(handles[loop], 0)) {
			case WAIT_ABANDONED:
				// ??
//				printf("A");
				break;
			case WAIT_TIMEOUT:
				// occurs if thread is active
//				printf("T");
				this->counts[1] ++;
				break;	
			case WAIT_OBJECT_0:
				// occurs if thread changes state to complete
//				printf("C");
				this->status[loop] = 2;
				CloseHandle(this->handles[loop]);
				this->counts[2] ++;
				break;
			case WAIT_FAILED:
//				printf("F");
				// occurs if thread is already complete
				if(GetLastError() == 6) {
					this->status[loop] = 2;
					CloseHandle(this->handles[loop]);
					this->counts[2] ++;	// count as a completed thread
				}
				else {
					// unknown error has occured
					exit(0);
				}
				break;
		}
	}
//	printf("\n");
}

// Find an active thread and watch it waiting for it to finish, return true
// If unable to find an active thread, return false
bool Block::waitForThread() {
	// loop through all threads
	for(int loop = 0; loop < this->size; loop ++) {
		// look for an active thread
		if(status[loop] == 1) {
			// check thread status
			switch(WaitForSingleObject(handles[loop], 200)) {
				case WAIT_ABANDONED:
					// ??
//					printf("A");
					break;
				case WAIT_TIMEOUT:
					// occurs if thread is active
//					printf("T");
					return true;
				case WAIT_OBJECT_0:
					// occurs if thread changes state to complete
//					printf("C");
					return true;
				case WAIT_FAILED:
//					printf("F");
					// occurs if thread is already complete
					if(GetLastError() == 6) {
						return true;
					}
					else {
						// unknown error has occured
						exit(0);
					}
					break;
			}
		}
	}

	return false;
}
*/